/**
 *Copyright (c) 2024 watereyes
 * workflow is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan
 * PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *          http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */
package com.koron.workflow.api.service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.ExtensionAttribute;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.StartEvent;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.ProcessDefinitionImpl;
import org.activiti.engine.impl.pvm.process.TransitionImpl;
import org.activiti.engine.impl.util.json.JSONObject;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.IdentityLink;
import org.activiti.engine.task.IdentityLinkType;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskInfo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.koron.workflow.api.dto.NextTaskNodeInfoDto;
import com.koron.workflow.api.dto.NodeInfoDto;
import com.koron.workflow.api.dto.TaskInfoDto;
import com.koron.workflow.common.bean.StaffBean;
import com.koron.workflow.common.exception.WorkflowException;
import com.koron.workflow.common.util.WorkflowUtil;

@Service
public class ActivitiService {
	
	@Autowired
	private IdentityService identityService;
	
	@Autowired
	private RepositoryService repositoryService;

	@Autowired
	private RuntimeService runtimeService;

	@Autowired
	private TaskService taskService;
	
	@Autowired
	private HistoryService historyService;
	
	private static final Map<String, BpmnModel> MODEL_CACHE = new HashMap<String, BpmnModel>();
	
	public ProcessDefinition getLastProcessDefinition(String processKey) {
		return repositoryService.createProcessDefinitionQuery().latestVersion().processDefinitionKey(processKey).singleResult();
	}
	
	public UserTask getDraftNode(String pdfId){
		Collection<FlowElement> flowElements = getFlowElements(pdfId);
		for (FlowElement one : flowElements) {
			if (one instanceof UserTask) {
				if(one.getExtensionElements().get("operation") != null) {
					Map<String, List<ExtensionAttribute>> operationmap = one.getExtensionElements().get("operation").get(0).getAttributes();
					if (null == operationmap) {
						throw new RuntimeException("节点属性获取失败!");
					}
					String type = operationmap.get("type").get(0).getValue();// 节点类型
					if (type.equals("draftNode")) {
						return (UserTask) one;
					}
				}
			}
		}
		return null;
	}
	
	public UserTask getUserTask(String pdfId, String id) {
		Collection<FlowElement> flowElements = getFlowElements(pdfId);
		for (FlowElement one : flowElements) {
			if (one instanceof UserTask && one.getId().equals(id)) {
				return (UserTask)one;
			}
		}
		return null;
	}
	
	public List<Map<String, String>> workflowDefine(String processKey) {
		ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey(processKey).active().latestVersion().singleResult();
        Objects.requireNonNull(processDefinition, "该流程模板不存在");
		Collection<FlowElement> flowElements = getFlowElements(processDefinition.getId());
        List<Map<String, String>> data = new ArrayList<Map<String, String>>();
        for (FlowElement element : flowElements) {
            if (element instanceof UserTask) { 
                UserTask task = (UserTask) element;
                Map<String, String> props = new HashMap<String, String>(); 
                props.put("nodeId", task.getId());
                props.put("nodeName", task.getName());
                List<ExtensionAttribute> codeAttr = task.getExtensionElements().get("operation").get(0).getAttributes().get("code");
                if(codeAttr != null && codeAttr.size() > 0) {
                	 props.put("nodeCode", codeAttr.get(0).getValue());
                }
                List<ExtensionAttribute> fromAttr = task.getExtensionElements().get("operation").get(0).getAttributes().get("from_id");
                if(fromAttr != null && fromAttr.size() > 0) {
                	props.put("formId", fromAttr.get(0).getValue());
                }else {
                	props.put("formId", "");
                }
                data.add(props);
            }
        }
        return data;
    }
	
	public boolean isDraftNode(TaskInfo task) {
		Collection<FlowElement> flowElements = getFlowElements(task.getProcessDefinitionId());
		for (FlowElement one : flowElements) {
			if (one instanceof UserTask && Objects.equals(one.getId(), task.getTaskDefinitionKey())) {
				Map<String, List<ExtensionAttribute>> operationmap = one.getExtensionElements().get("operation").get(0).getAttributes();
				String type = operationmap.get("type").get(0).getValue();// 节点类型
				if (type.equals("draftNode")) {
					return true;
				}
			}
		}
		return false;
	}
	
	public boolean isNullOperatorSkip(TaskInfo task, List<String> userList) {
		boolean isNullOperatorSkip = false;
		Collection<FlowElement> flowElements = getFlowElements(task.getProcessDefinitionId());
		for (FlowElement one : flowElements) {
			if (one instanceof UserTask && Objects.equals(one.getId(), task.getTaskDefinitionKey())) {
				Map<String, List<ExtensionAttribute>> operationmap = one.getExtensionElements().get("operation").get(0).getAttributes();
				String value = operationmap.get("null_operator_skip").get(0).getValue();// 节点类型
				if(StringUtils.isNotBlank(value) && Boolean.parseBoolean(value)) {
					isNullOperatorSkip = true;
				}
			}
		}
		if(isNullOperatorSkip && (userList == null || userList.size() == 0)) {
			return true;
		}else {
			return false;
		}
	}
	
	public boolean isDoubleSkip(TaskInfo task, List<String> userList, String mode, String loopCounter) {
		boolean isDoubleSkip = false;
		Collection<FlowElement> flowElements = getFlowElements(task.getProcessDefinitionId());
		for (FlowElement one : flowElements) {
			if (one instanceof UserTask && Objects.equals(one.getId(), task.getTaskDefinitionKey())) {
				Map<String, List<ExtensionAttribute>> operationmap = one.getExtensionElements().get("operation").get(0).getAttributes();
				String value = operationmap.get("double_skip").get(0).getValue();// 节点类型
				if(StringUtils.isNotBlank(value) && Boolean.parseBoolean(value)) {
					isDoubleSkip = true;
				}
			}
		}
		if("2".equals(mode) || "3".equals(mode)) {
			String user = userList.get(Integer.parseInt(loopCounter));
			userList = Arrays.asList(user);
		}
		if(isDoubleSkip) {
			List<HistoricTaskInstance> hisTasks = historyService.createHistoricTaskInstanceQuery().processInstanceId(task.getProcessInstanceId()).list();
			List<String> assignees = hisTasks.stream().filter(t -> t.getAssignee() != null).map(t -> t.getAssignee()).collect(Collectors.toList());
			if(assignees.containsAll(userList)) {
				isDoubleSkip = true;
			}else {
				isDoubleSkip = false;
			}
		}
		return isDoubleSkip;
	}
	
	public boolean isApprovalNode(TaskInfo task) {
		Collection<FlowElement> flowElements = getFlowElements(task.getProcessDefinitionId());
		for (FlowElement one : flowElements) {
			if (one instanceof UserTask && Objects.equals(one.getId(), task.getTaskDefinitionKey())) {
				Map<String, List<ExtensionAttribute>> operationmap = one.getExtensionElements().get("operation").get(0).getAttributes();
				String type = operationmap.get("type").get(0).getValue();// 节点类型
				if (type.equals("approveNode")) {
					return true;
				}
			}
		}
		return false;
	}
	
	public String getCirculationMode(TaskInfo task) {
		Collection<FlowElement> flowElements = getFlowElements(task.getProcessDefinitionId());
		for (FlowElement one : flowElements) {
			if (one instanceof UserTask && Objects.equals(one.getId(), task.getTaskDefinitionKey())) {
				Map<String, List<ExtensionAttribute>> operationmap = one.getExtensionElements().get("operation").get(0).getAttributes();
				return operationmap.get("circulation_mode") == null ? StringUtils.EMPTY : operationmap.get("circulation_mode").get(0).getValue();
			}
		}
		return StringUtils.EMPTY;
	}
	
	public String getFilterRule(TaskInfo task) {
		Collection<FlowElement> flowElements = getFlowElements(task.getProcessDefinitionId());
		for (FlowElement one : flowElements) {
			if (one instanceof UserTask && Objects.equals(one.getId(), task.getTaskDefinitionKey())) {
				Map<String, List<ExtensionAttribute>> operationmap = one.getExtensionElements().get("operation").get(0).getAttributes();
				return operationmap.get("filter_rule") == null ? StringUtils.EMPTY : operationmap.get("filter_rule").get(0).getValue();// 节点类型
			}
		}
		return StringUtils.EMPTY;
	}
	
	public String getAutoPickRule(TaskInfo task) {
		Collection<FlowElement> flowElements = getFlowElements(task.getProcessDefinitionId());
		for (FlowElement one : flowElements) {
			if (one instanceof UserTask && Objects.equals(one.getId(), task.getTaskDefinitionKey())) {
				Map<String, List<ExtensionAttribute>> operationmap = one.getExtensionElements().get("operation").get(0).getAttributes();
				return operationmap.get("auto_pick_rule") == null ? StringUtils.EMPTY : operationmap.get("auto_pick_rule").get(0).getValue();// 节点类型
			}
		}
		return StringUtils.EMPTY;
	}
	
	public boolean isSubTaskNode(TaskInfo task) {
		Collection<FlowElement> flowElements = getFlowElements(task.getProcessDefinitionId());
		for (FlowElement one : flowElements) {
			if (one instanceof UserTask && Objects.equals(one.getId(), task.getTaskDefinitionKey())) {
				Map<String, List<ExtensionAttribute>> operationmap = one.getExtensionElements().get("operation").get(0).getAttributes();
				if(operationmap.get("type") == null) {
					return false;
				}
				String type = operationmap.get("type").get(0).getValue();// 节点类型
				if (type.equals("subFlowNode")) {
					return true;
				}
			}
		}
		return false;
	}
	
	public String getTaskCode(TaskInfo task) {
		Collection<FlowElement> flowElements = getFlowElements(task.getProcessDefinitionId());
		for (FlowElement one : flowElements) {
			if (one instanceof UserTask && Objects.equals(one.getId(), task.getTaskDefinitionKey())) {
				if(one.getExtensionElements().get("operation") != null) {
					Map<String, List<ExtensionAttribute>> operationmap = one.getExtensionElements().get("operation").get(0).getAttributes();
					return operationmap.get("code") == null ? StringUtils.EMPTY : operationmap.get("code").get(0).getValue();// 节点类型
				}
			}
		}
		return StringUtils.EMPTY;
	}
	
	/**
	 * 通过用户节点的code获取用户节点的ID
	 * @param processDefinitionId
	 * @param taskCode
	 * @return
	 */
	public String getTaskKeyByCode(String processDefinitionId, String taskCode) {
		Collection<FlowElement> flowElements = getFlowElements(processDefinitionId);
		for (FlowElement one : flowElements) {
			if (one instanceof UserTask) {
				if(one.getExtensionElements() != null && one.getExtensionElements().get("operation") != null) {
					Map<String, List<ExtensionAttribute>> operationmap = one.getExtensionElements().get("operation").get(0).getAttributes();
					if(operationmap.get("code") != null && Objects.equals(operationmap.get("code").get(0).getValue(), taskCode)) {
						return one.getId();
					}
				}
			}
		}
		return StringUtils.EMPTY;
	}
	
	 /**
     * 获取节点扩展属性
     * @param task
     * @param flowElements
     * @return
     */
    public Map<String, Object> nodeParam(Task task, Collection<FlowElement> flowElements) {
        Map<String, Object> param = new HashMap<>();
        Map<String, List<ExtensionAttribute>> map = null;
        for (FlowElement ele : flowElements) {
			if (ele instanceof UserTask && ele.getId().equals(task.getTaskDefinitionKey())) {
				map = ele.getExtensionElements().get("operation").get(0).getAttributes();
				break;
			}
		}
        String[] modnodes = map.get("can_update_nodes").get(0).getValue().split(",", -1);//可修改的节点
        String[] mmodnodes = map.get("must_update_nodes").get(0).getValue().split(",", -1);//必须修改的节点
        List<Map<String, String>> modnodeses = new ArrayList<>();
        List<Map<String, String>> mmodnodeses = new ArrayList<>();
        for (FlowElement ele : flowElements) {
            if (ele instanceof StartEvent || ele instanceof UserTask) {
                if (modnodes != null && modnodes.length != 0) {
                    for (int i = 0; i < modnodes.length; i++) {
                        if (ele.getId().equals(modnodes[i])) {
                            Map<String, String> nodemap = new HashMap<String, String>();
                            nodemap.put(ele.getId(), ele.getName());
                            modnodeses.add(nodemap);
                        }
                    }
                }
                if (mmodnodes != null && mmodnodes.length != 0) {
                    for (int i = 0; i < mmodnodes.length; i++) {
                        if (ele.getId().equals(mmodnodes[i])) {
                            Map<String, String> nodemap = new HashMap<String, String>();
                            nodemap.put(ele.getId(), ele.getName());
                            mmodnodeses.add(nodemap);
                        }
                    }
                }
            }
        }
        String type = map.get("type").get(0).getValue();//节点类型
        /**
         * attachment:审批意见中上传附件;noticedraftman:通知起草人;formid:表单ID;modprocess:可修改流程;defh:默认处理人;nulldefskip:处理人为空跳过;
         * dupidskip:身份重复跳过;circulationmode:流转方式;mdocedition:编辑主文档;optdefn:操作定义;opttmpl:操作模板;customopt:自定义操作;
         * urgehandler:催办处理人;noticedraftman:通知起草人;noticepv:通知特权人;autoskip:自动跳过;modnodes:可修改的节点;mmodnodes:必须修改的节点;
         */
        switch (type) {
            case "draftNode":{
                setParams(param, map, "notice_way", "attachment", "notice_draft_man", "form_id", "candidate", "type");
                param.put("can_update_nodes", modnodeses);
                param.put("must_update_nodes", mmodnodeses);
                param.put("options", "0");//zxy 避免后结这个字段为空报错
                break;
            }
            case "noticeNode":{
                setParams(param, map, "notice_way", "candidate");
                break;
            }
            case "approveNode":{
                setParams(param, map, "notice_way", "candidate", "null_operator_skip", "double_skip", "circulation_mode", "attachment",
                        "options", "notice_draft_man", "auto_skip", "form_id", "type");
                param.put("can_update_nodes", modnodeses);
                param.put("must_update_nodes", mmodnodeses);
                break;
            }
            default:
                break;
        }
        return param;
    }
    
	public void activateProcessInstance(String processInstanceId) {
		runtimeService.activateProcessInstanceById(processInstanceId);
	}
	
	public Object getVariable(String taskId, String variableName) {
		return taskService.getVariable(taskId, variableName);
	}
	
	/**
	 * 通过流程实例ID获取流程当前的实例
	 * @param processInstanceId
	 * @return
	 */
	public ProcessInstance getProcessInstance(String processInstanceId){
		return runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
	}
	
	public void transferAssignee(String taskId, String user) {
		taskService.delegateTask(taskId, user);
	}
	
	public void backProcess(Task task, String title, String operator, String rejectNodeCode, Map<String, Object> variables) {
		variables.put("taskId", task.getId());
		variables.put("operator", operator);
		variables.put("title", title);
		variables.put("operation", WorkflowService.OPERATION_REJECT + "");
		String mode = getCirculationMode(task);
		String activitiKey = getTaskKeyByCode(task.getProcessDefinitionId(), rejectNodeCode);
		if("2".equals(mode) || "3".equals(mode)) {
			String variableName = "Loop" + task.getTaskDefinitionKey().replaceAll("-", "") + "_User_List";
			List<String> users = runtimeService.getVariable(task.getExecutionId(), variableName, List.class);
			if(users != null && users.size() > 0) {
				variables.put("nrOfCompletedInstances", users.size() - 1);
				variables.put("loopCounter", users.size() - 1);
			}
		}
		turnTransition(task, activitiKey, variables);
	}

	public List<String> getCandidateUsers(Task task, Map<String, Object> variable) {
		@SuppressWarnings("unchecked")
		List<String> users = (List<String>) runtimeService.getVariable(task.getExecutionId(), task.getTaskDefinitionKey().replaceAll("-", "") + "_User");
		//users = ApiUtils.convertUsers(users, variable);
		if (users.size() == 1) {
			users = Arrays.stream(users.get(0).split(",")).collect(Collectors.toList());
		}
	   return users;
	}
	
	public void addCandidateUsers(String taskId, List<String> users) {
	    for (String user : users) {
            taskService.addCandidateUser(taskId, user);
        }
	}
	
	public void addCandidateUser(String taskId, String user) {
        taskService.addCandidateUser(taskId, user);
	}
	
	public void deleteProcessInstance(String processInstanceId) {
		List<Task> tasks = getTaskByProcessInsId(processInstanceId);
		if(tasks != null && tasks.size() > 0) {
			runtimeService.deleteProcessInstance(processInstanceId, "初始化");
		}
		historyService.deleteHistoricProcessInstance(processInstanceId);
	}
	
	public void deleteCandidateUser(String taskId, String user) {
        taskService.deleteCandidateUser(taskId, user);
	}
	
	public void suspendProcessInstance(String processInstanceId) {
		runtimeService.suspendProcessInstanceById(processInstanceId);
	}
	
	public NextTaskNodeInfoDto getNextTaskNodeInfoDto(List<Task> tasks){
		NextTaskNodeInfoDto nextTaskInfo = new NextTaskNodeInfoDto();
		List<NodeInfoDto> nodeInfos = new ArrayList<NodeInfoDto>();
		List<TaskInfoDto> taskInfos = new ArrayList<TaskInfoDto>();
		nextTaskInfo.setCurNodes(nodeInfos);
		nextTaskInfo.setTasks(taskInfos);
		if(tasks == null || tasks.size() == 0) {
			nodeInfos.add(new NodeInfoDto("END", "结束"));
			return nextTaskInfo;
		}
		for(Task task : tasks) {
			if(task.isSuspended()) {
				nodeInfos.add(new NodeInfoDto("CANCEL", "废弃"));
				return nextTaskInfo;
			}
			if(!isSubTaskNode(task)) {
				nextTaskInfo.setProcessInstanceId(task.getProcessInstanceId());
				List<String> candidateUsers = getCandidateUsers(task.getId());
				List<StaffBean> staffs = WorkflowUtil.getStaffByAccount(candidateUsers);
				String userNames = staffs.stream().map(t -> t.getName()).collect(Collectors.joining(","));
				nodeInfos.add(new NodeInfoDto(getTaskCode(task), task.getName()));
				String taskCode = getTaskCode(task);
				taskInfos.add(new TaskInfoDto(StringUtils.join(candidateUsers, ","), userNames, task.getId(), taskCode, task.getName()));
			}
		}
		return nextTaskInfo;
	}
	
	/**
	 * 获取流程中所有的子流程节点
	 * @param task
	 * @return
	 */
	public String getSubTaskCode(Task task){
		Collection<FlowElement> flowElements = getFlowElements(task.getProcessDefinitionId());
		for (FlowElement one : flowElements) {
			if (one instanceof UserTask && Objects.equals(one.getId(), task.getTaskDefinitionKey())) {
				Map<String, List<ExtensionAttribute>> operationmap = one.getExtensionElements().get("operation").get(0).getAttributes();
				List<ExtensionAttribute> extensionAttributes = operationmap.get("sub_flow");// 节点类型
				if(extensionAttributes != null && extensionAttributes.size() > 0) {
					return extensionAttributes.get(0).getValue();
				}
			}
		}
		return StringUtils.EMPTY;
	}
	
	public void complete(String taskId, String operator, String title, Map<String, Object> variable) {
		variable.put("taskId", taskId);
		variable.put("operator", operator);
		variable.put("title", title);
		variable.put("operation", WorkflowService.OPERATION_AGREE + "");
		taskService.claim(taskId, operator);  //签收任务
        taskService.complete(taskId, variable); //节点办理
	}
	
	public void saveOtherNodeCandidates(String otherNodeCandidates, String executionId){
        if (StringUtils.isNotEmpty(otherNodeCandidates)) {
        	Map<String, Object> candidatesMap = new HashMap<String, Object>();
        	try {
        		JSONObject njo = new JSONObject(otherNodeCandidates);
                Iterator<?> it = njo.keys();
                while (it.hasNext()) {
                    String nodeid = it.next().toString();
                    List<String> users = Arrays.asList(njo.get(nodeid).toString().split(","));
                    for(int i = 0; i < users.size(); i++) {
                    	if(users.get(i).startsWith("1-")) {
                    		continue;
                    	}
                    	users.set(i, "1-" + users.get(i)); // 1- 代表是职员
                    }               
                    candidatesMap.put(nodeid.replaceAll("-", "") + "_User", users);
                }
                candidatesMap.forEach((k, v) -> runtimeService.setVariable(executionId, k, v));
        	} catch(Exception ex) {
        		throw new WorkflowException("设置下一步节点处理人失败！");
        	}
        }
	}
	
	public ProcessInstance startProcessInstanceByKey(String processKey, String operator, String title, String billId, Map<String, Object> variable) {
		try{
			variable.put("operation", WorkflowService.OPERATION_AGREE + "");
			variable.put("title", title);
			identityService.setAuthenticatedUserId(operator);
			return runtimeService.startProcessInstanceByKey(processKey, billId, variable);
		}finally {
			identityService.setAuthenticatedUserId(null);
		}
	}
	
	public Collection<FlowElement> getFlowElements(String processDefId){
		BpmnModel model = MODEL_CACHE.get(processDefId);
		if(model == null) {
			model = repositoryService.getBpmnModel(processDefId);
			MODEL_CACHE.put(processDefId, model);
		}
		return model.getProcesses().get(0).getFlowElements();
	}
	
	public List<Task> getTaskByProcessInsId(String processInsId){
		return taskService.createTaskQuery().processInstanceId(processInsId).list();
	}
	
	public List<Task> getTaskByExecutionId(String executionId){
		return taskService.createTaskQuery().executionId(executionId).list();
	}
	
	public Task getTaskById(String taskId){
		return taskService.createTaskQuery().taskId(taskId).singleResult();
	}
	
	public HistoricTaskInstance getHistoricTaskById(String taskId) {
		return historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult();
	}
	
	public List<HistoricTaskInstance> getHistoricTaskByProcessInsId(String processInsId) {
		return historyService.createHistoricTaskInstanceQuery().processInstanceId(processInsId).finished().orderByHistoricTaskInstanceEndTime().asc().list();
	}
	
	public List<IdentityLink> getIdentityLinkByTaskId(String taskId){
		return taskService.getIdentityLinksForTask(taskId);
	}
	
	public void deleteCandidateUsers(String taskId) {
		List<String> users = getCandidateUsers(taskId);
		List<String> newUsers = new ArrayList<>(users);
		for(String u : newUsers) {
			taskService.deleteUserIdentityLink(taskId, u, IdentityLinkType.CANDIDATE);
		}
	}
	
	public List<String> getCandidateUsers(String taskId){
		List<IdentityLink> identityLinks = getIdentityLinkByTaskId(taskId);
		if(identityLinks == null || identityLinks.size() == 0) {
			return Collections.emptyList();
		}
		return identityLinks.stream().filter(item -> item.getType().equals("candidate")).map(item -> item.getUserId()).collect(Collectors.toList());
	}
	
	public HistoricProcessInstance getHistoricProcessInstance(String processInsId) {
		return historyService.createHistoricProcessInstanceQuery().processInstanceId(processInsId).singleResult();
	}
	
	private ProcessDefinitionEntity findProcessDefinitionEntityById(String id) {  
        return (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService).getDeployedProcessDefinition(id);  
    }  
	
	 private void turnTransition(Task task, String activityId, Map<String, Object> variables) {  
		ActivityImpl currActivity = null;
		List<PvmTransition> oriPvmTransitionList = null;
        try {
        	 // 当前节点  
        	 currActivity = findActivitiImpl(task.getProcessDefinitionId(), task.getId(), null);  
             // 清空当前流向  
             oriPvmTransitionList = clearTransition(currActivity);  
             // 创建新流向  
             TransitionImpl newTransition = currActivity.createOutgoingTransition();  
             // 目标节点  
             ActivityImpl pointActivity = findActivitiImpl(task.getProcessDefinitionId(), task.getId(), activityId);
             // 设置新流向的目标节点  
             newTransition.setDestination(pointActivity);  
             // 执行转向任务  
         	taskService.complete(task.getId(), variables);  
             // 删除目标节点新流入  
             pointActivity.getIncomingTransitions().remove(newTransition); 
		} finally {
			 // 还原以前流向  
	        restoreTransition(currActivity, oriPvmTransitionList);  
		}
    }
	 
   /** 
     * 清空指定活动节点流向 
     *  
     * @param activityImpl 
     *            活动节点 
     * @return 节点流向集合 
     */  
    private List<PvmTransition> clearTransition(ActivityImpl activityImpl) {  
        // 存储当前节点所有流向临时变量  
        List<PvmTransition> oriPvmTransitionList = new ArrayList<PvmTransition>();  
        // 获取当前节点所有流向，存储到临时变量，然后清空  
        List<PvmTransition> pvmTransitionList = activityImpl.getOutgoingTransitions();  
        for (PvmTransition pvmTransition : pvmTransitionList) {  
            oriPvmTransitionList.add(pvmTransition);  
        }  
        pvmTransitionList.clear();  
  
        return oriPvmTransitionList;  
    } 
    
    /** 
     * 还原指定活动节点流向 
     *  
     * @param activityImpl 
     *            活动节点 
     * @param oriPvmTransitionList 
     *            原有节点流向集合 
     */  
    private void restoreTransition(ActivityImpl activityImpl, List<PvmTransition> oriPvmTransitionList) {  
        if(activityImpl != null) {
        	// 清空现有流向  
            List<PvmTransition> pvmTransitionList = activityImpl.getOutgoingTransitions();  
            pvmTransitionList.clear();  
            // 还原以前流向  
            for (PvmTransition pvmTransition : oriPvmTransitionList) {  
                pvmTransitionList.add(pvmTransition);  
            }  
        }
    } 
    
    private ActivityImpl findActivitiImpl(String processDefId, String taskId, String activityId) {
        // 取得流程定义  
        ProcessDefinitionEntity processDefinition = findProcessDefinitionEntityById(processDefId);  
        if (StringUtils.isEmpty(activityId)) {
            activityId = getTaskById(taskId).getTaskDefinitionKey();  
        }
        // 根据流程定义，获取该流程实例的结束节点   Process-end0
        if (activityId.toUpperCase().equals("PROCESS-END0")) {  
            for (ActivityImpl activityImpl : processDefinition.getActivities()) {  
                List<PvmTransition> pvmTransitionList = activityImpl.getOutgoingTransitions();  
                if (pvmTransitionList.isEmpty()) {
                    return activityImpl;  
                }
            }
        }  
        // 根据节点ID，获取对应的活动节点  
        return((ProcessDefinitionImpl) processDefinition).findActivity(activityId);  
    }
    
    private Map<String, Object> setParams(Map<String, Object> param, Map<String, List<ExtensionAttribute>> map, String... adds) {
        for (String one : adds) {
            param.put(one, map.get(one).get(0).getValue());
        }
        return param;
    }
}
